package org.dromara.ueditorplus;

import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import lombok.AllArgsConstructor;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.dromara.config.UEditorConfig;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author YWQ
 * @date 2025/7/3 14:35
 * @description 富文本编辑器后端配置接口
 */
@RestController
@AllArgsConstructor
@RequestMapping("/ueditorPlus")
public class UEditorPlusController {

    private final UEditorConfig ueditorConfig;

    private final ISysOssService ossService;


    @RequestMapping
    public void controller(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String action = request.getParameter("action");
        UEditorResult result = new UEditorResult();
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        if ("config".equals(action)) {
            response.getWriter().write(getConfig().toString());
        } else if (action != null && action.startsWith("upload")) {
            result = handleUpload(request, action,result);
            response.getWriter().write(JSONUtil.toJsonStr(result));
        } else if ("listimage".equals(action) || "listfile".equals(action)) {
            result = listFiles(request, action,result);
        } else if ("catchimage".equals(action)) {
            result = catchImage(request,result);
        } else {
            throw  new RuntimeException("Unsupported action: " + action);
        }
    }

    private JSONObject getConfig() throws IOException {
        ClassPathResource resource = new ClassPathResource(ueditorConfig.getConfig().getConfigFile());
        String configJson = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        return JSONUtil.parseObj(configJson);
    }

    private UEditorResult handleUpload(HttpServletRequest request, String action,UEditorResult result) {
        // 获取 Content-Type 头
        String contentType = request.getContentType();
        Assert.isFalse(contentType != null && contentType.toLowerCase().startsWith("multipart/form-data"), "请求必须为 multipart/form-data 类型");
        // 解析上传的文件（Servlet 3.0+ 内置支持）
        Collection<Part> parts = null;
        try {
            parts = request.getParts();
            Iterator<Part> iterator = parts.iterator();
            while (iterator.hasNext()) {
                Part part = iterator.next();
                // 跳过表单字段
                if (part.getName() == null || part.getSize() <= 0) {
                    continue;
                }

                // 获取文件名
                String fileName = getFileName(part);
                if (!StringUtils.hasText(fileName)) {
                    continue;
                }

                // 返回处理结果
                result = processUploadedFileByPart(part, action, fileName,result);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ServletException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    // 使用Part处理上传文件
    private UEditorResult processUploadedFileByPart(Part part, String action, String originalFilename,UEditorResult result) {

        // 获取文件扩展名
        String fileExt = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();

        // 验证文件类型
        List<String> allowedExtensions;
        switch (action) {
            case "uploadimage":
                allowedExtensions = ueditorConfig.getUpload().getImageAllowFiles();
                break;
            case "uploadfile":
                allowedExtensions = ueditorConfig.getUpload().getFileAllowFiles();
                break;
            case "uploadvideo":
                allowedExtensions = ueditorConfig.getUpload().getVideoAllowFiles();
                break;
            default:
                allowedExtensions = Collections.emptyList();
        }
        //断言
        Assert.isTrue(!allowedExtensions.contains(fileExt),"不允许的文件类型: " + fileExt);

        SysOssVo oss = ossService.upload((MultipartFile) part);
        String url = oss.getUrl();

        result.setState("SUCCESS");
        result.setOriginal(originalFilename);
        result.setUrl(url);
        result.setTitle(originalFilename);
        return result;
    }

    // 从Part中提取文件名
    private String getFileName(Part part) {
        String contentDisposition = part.getHeader("content-disposition");
        if (contentDisposition != null) {
            for (String cd : contentDisposition.split(";")) {
                if (cd.trim().startsWith("filename")) {
                    String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                    int index = filename.lastIndexOf(File.separator);
                    return filename.substring(index + 1);
                }
            }
        }
        return null;
    }


    private UEditorResult listFiles(HttpServletRequest request, String action,UEditorResult result) {
        int start = getIntParam(request, "start", 0);
        int size = getIntParam(request, "size", 20);

        File dir = new File(ueditorConfig.getUpload().getBaseDir());
        File[] files = dir.listFiles();
        Assert.isNull(files, "目录不存在");

        // 过滤文件类型
        List<String> allowedExtensions = "listimage".equals(action) ?
                ueditorConfig.getUpload().getImageAllowFiles() :
                ueditorConfig.getUpload().getFileAllowFiles();

        List<UEditorResult> fileList = new ArrayList<>();
        int total = 0;

        for (File file : files) {
            if (file.isFile()) {
                String ext = getFileExtension(file.getName());
                if (allowedExtensions.contains(ext.toLowerCase())) {
                    if (total >= start && fileList.size() < size) {
                        UEditorResult fileInfo = new UEditorResult();
                        fileInfo.setUrl(ueditorConfig.getUpload().getAccessPath() + file.getName());
                        fileInfo.setMtime(file.lastModified());
                        fileList.add(fileInfo);
                    }
                    total++;
                }
            }
        }

        result.setState("SUCCESS");
        result.setList(fileList);
        result.setTotal(total);
        result.setStart(start);
        result.setSize(size);
        return result;
    }

    private UEditorResult catchImage(HttpServletRequest request,UEditorResult result) {
        String[] sources = request.getParameterValues("source[]");
        Assert.isTrue(sources == null || sources.length == 0, "未指定抓取源");

        List<UEditorResult> list = new ArrayList<>();
        for (String source : sources) {
            UEditorResult item = new UEditorResult();
            try {
                URL url = new URL(source);
                String fileExt = getFileExtension(source);

                if (!ueditorConfig.getUpload().getImageAllowFiles().contains(fileExt.toLowerCase())) {
                    item.setState("不允许的图片类型");
                    continue;
                }

                // 下载图片
                String fileName = generateNewFileName(fileExt);
                File dest = new File(ueditorConfig.getUpload().getBaseDir(), fileName);
                try (InputStream in = url.openStream();
                     FileOutputStream out = new FileOutputStream(dest)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = in.read(buffer)) != -1) {
                        out.write(buffer, 0, bytesRead);
                    }
                }

                item.setState("SUCCESS");
                item.setSource(source);
                item.setUrl(ueditorConfig.getUpload().getAccessPath() + fileName);
            } catch (Exception e) {
                item.setState("抓取失败: " + e.getMessage());
            }
            list.add(item);
        }

        result.setState(list.isEmpty() ? "ERROR" : "SUCCESS");
        result.setList(list);
        return result;
    }

    // 辅助方法
    private String generateNewFileName(String ext) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return "ueditor_" + sdf.format(new Date()) + "_" +
                UUID.randomUUID().toString().substring(0, 8) + ext;
    }

    private String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        return (dotIndex == -1) ? "" : fileName.substring(dotIndex);
    }

    private JSONObject errorResult(String message) {
        JSONObject result = new JSONObject();
        result.put("state", message);
        return result;
    }

    private int getIntParam(HttpServletRequest request, String param, int defaultValue) {
        try {
            return Integer.parseInt(request.getParameter(param));
        } catch (Exception e) {
            return defaultValue;
        }
    }

}
